home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9005.ZIP
/
SYCK.LST
< prev
next >
Wrap
File List
|
1990-03-23
|
17KB
|
689 lines
_DLLs FOR DOS_
by Gary Syck
[LISTING ONE]
// GETDATA.C Read GBLDATA.OBJ to get global variables for DLLs
// 02/12/89 by Gary Syck
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include "dll.h"
// Open GBLDATA and read data
void
GetData()
{
int fd; // File descriptor for GBLDATA.OBJ
int Idx; // Index numbers from the file
unsigned long Elmnts, DSize; // Number and size of global data items
unsigned PubGrp, PubSeg; // Group and segment indexes for data
unsigned DOff; // Offset for initialized data
unsigned char type; // type of record read
int size; // size of the record
unsigned char *Data; // the data to read
unsigned char *DSptr; // Pointer to the Data segment
int i, j;
if((fd=open( "gbldata.obj", O_BINARY|O_RDONLY )) == -1 )
{
printf( "Unable to open file\n" );
exit(1);
}
DataSize = 0;
SymCnt = 0;
AllocNumb = 0;
SymSize = 0;
type = 0;
DSptr = &DataSpace;
while( type != MODEND )
{
read( fd, (char *) &type, sizeof( unsigned char ));
read( fd, (char *) &size, sizeof( int ));
Data = malloc( size );
read( fd, Data, size );
switch( type )
{
case PUBDEF: // The record contains public symbols
i=0;
if( Data[i]&0x80 )
{
PubGrp = (Data[i++]&0x7f)<<8;
PubGrp += Data[i++];
}
else
PubGrp = Data[i++];
if( Data[i]&0x80 )
{
PubSeg = (Data[i++]&0x7f)<<8;
PubSeg += Data[i++];
}
else
PubSeg = Data[i++];
if( PubSeg == 0 )
i += 2; // skip the frame number
AllocateSyms(); // make memory for all symbols
/* assume all public defs are in the DGROUP */
while( i<size-1 )
{
Syms[SymCnt].Name = malloc( Data[i] + 2 );
strncpy( Syms[SymCnt].Name, &Data[i+1], Data[i] );
Syms[SymCnt].Name[Data[i]] = '\0';
i += Data[i]+1;
Syms[SymCnt].Seg = FP_SEG(DSptr);
Syms[SymCnt].Offset = (FP_OFF(DSptr))+ *((int *) &Data[i] );
SymCnt++;
i += 2;
if( Data[i]&0x80 ) // skip over the type
{
Idx = (Data[i++]&0x7f)<<8;
Idx += Data[i++];
}
else
Idx = Data[i++];
}
break;
case LEDATA: // record contains data for data segment
i = 0;
if( Data[i]&0x80 )
{
Idx = (Data[i++]&0x7f)<<8;
Idx += Data[i++];
}
else
Idx = Data[i++];
/* Assume all data is for the data segment */
DOff = *((int *) &Data[i] );
i += 2;
memcpy( &DSptr[DOff], &Data[i], size-(i+1) );
if( DataSize < DOff + size - (i+1))
DataSize = DOff + size - (i+1);
break;
case COMDEF: // record contains uninitialized data
i = 0;
while( i < size-1 )
{
Syms[SymCnt].Name = malloc( Data[i]+2 );
strncpy( Syms[SymCnt].Name, &Data[i+1], Data[i] );
Syms[SymCnt].Name[Data[i]] = '\0';
i += Data[i] + 2;
if( Data[i++] == 0x61 )
{
if( Data[i] < 128 )
Elmnts = (unsigned long) Data[i++];
else
{
j = Data[i++] - 127;
Elmnts = 0L;
memcpy( &Elmnts, &Data[i], j );
i += j;
}
if( Data[i] < 128 )
DSize = (unsigned long) Data[i++];
else
{
j = Data[i++] - 127;
DSize = 0L;
memcpy( &DSize, &Data[i], j );
i += j;
}
Syms[SymCnt].Size = (unsigned) (Elmnts * DSize);
if( (unsigned long) SymSize + (unsigned long) (Elmnts * DSize) >= 32000L )
AllocateSyms();
SymSize += (unsigned) (Elmnts * DSize);
SymCnt++;
}
}
break;
default:
break;
}
free( Data );
}
close( fd );
AllocateSyms(); // make memory for all of the symbols
}
// make a memory block to hold the previous symbols
void
AllocateSyms()
{
char *Buff;
unsigned Seg, Off;
if( SymSize )
{
Buff = malloc( SymSize );
Seg = FP_SEG( Buff );
Off = FP_OFF( Buff );
SymSize = 0;
while( AllocNumb < SymCnt )
{
Syms[AllocNumb].Seg = Seg;
Syms[AllocNumb].Offset = Off;
Off += Syms[AllocNumb].Size;
AllocNumb++;
}
}
}
[LISTING TWO]
; STUB.ASM Used by DLL to see if a function needs to be loaded.
; 02/12/89 By Gary Syck
TITLE stub.asm
NAME stub
.8087
STUB_TEXT SEGMENT WORD PUBLIC 'CODE'
STUB_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
DGROUP GROUP CONST, _BSS, _DATA
ASSUME CS: STUB_TEXT, DS: DGROUP, SS: DGROUP
EXTRN _LoadFunc:FAR ; Function to get a function into memory
EXTRN _FuncLst:DWORD ; The function table
_DATA SEGMENT
PUBLIC _DataSpace
_DataSpace db 32000 dup(?)
_DATA ENDS
STUB_TEXT SEGMENT
ASSUME CS: STUB_TEXT
PUBLIC _Stub
_Stub PROC FAR
mov bx,offset _FuncLst ; this is modified before use
mov ax,seg _FuncLst
mov es,ax
mov ax,WORD PTR es:[bx+4] ; check .Loc
or ax,WORD PTR es:[bx+6]
jne noload
push es ; save ES and BX
push bx
call FAR PTR _LoadFunc
pop bx
pop es
noload:
jmp DWORD PTR es:[bx+4] ; go to the function
_Stub ENDP
STUB_TEXT ENDS
END
[LISTING THREE]
// LINKER.C Link a module at run time
// 02/12/89 by Gary Syck
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include <stdlib.h>
#include "dll.h"
// Load the function in the FUNCTAB entry
void
LoadFunc( FUNCTAB *func )
{
char FileName[15], *p, Name[80];
int fd;
unsigned char type;
int size;
unsigned char *Data, *Dp, *LastFunc;
int i, j, ln;
unsigned pubgrp, pubseg, dataseg;
unsigned DROff, Loc, FixDat;
unsigned FrameIdx, TargetIdx, TargetDisp, tmp;
unsigned long ltmp;
int dataoff;
unsigned LocalSize; // size of the data allocated here
struct {
int Flag; // 1 = data, 2 = function
int SymNumb; // What symbol
} ExtSyms[20];
int ExtCnt;
struct {
int FuncNumb;
int OffSet;
} Pubs[10];
int PubCnt;
struct {
unsigned Meth; // The method to use
unsigned Idx; // The index
} Threads[8];
void *ptr;
unsigned char *DSptr;
unsigned constseg; // Where constants begin
strncpy( FileName, &func->Name[1], 14 );
FileName[14] = '\0';
if((p=strchr( FileName, '#' )) != NULL )
*p = '\0';
strcat( FileName, ".obj" );
if((fd=open( FileName, O_RDONLY|O_BINARY )) == -1 )
{
printf( "Unable to open file: %s\n", FileName );
return;
}
LocalSize = 0;
ExtCnt = 0;
PubCnt = 0;
type = 0;
DSptr = &DataSpace;
while( type != MODEND )
{
read( fd, (char *) &type, sizeof( unsigned char ));
read( fd, (char *) &size, sizeof( int ));
Data = malloc( size );
read( fd, Data, size );
switch( type )
{
case THEADR: // ignore the header
case COMMENT: // ignore comments
case GRPDEF: // these are always the same
case MODEND:
case SEGDEF:
case LNAMES:
break;
case EXTDEF: // find external names
for( i=0; i<size-1; i += ln+2 )
{
ln = Data[i];
if( ln )
{
strncpy( Name, &Data[i+1], ln );
Name[ln] = '\0';
for( j=0; j<SymCnt && strcmp(Syms[j].Name, Name );j++);
if( j<SymCnt )
{
ExtSyms[ExtCnt].Flag = 1;
ExtSyms[ExtCnt].SymNumb = j;
}
else
{
for( j=0; j<FuncCnt
&& strcmp( FuncLst[j].Name,Name );j++);
if( j>=FuncCnt ) // make space for it
{
FuncLst[FuncCnt].Name =
malloc(strlen(Name)+2 );
strcpy( FuncLst[FuncCnt].Name, Name );
FuncLst[FuncCnt].Loc = NULL;
FuncLst[FuncCnt].Flag = 0;
memcpy( FuncLst[FuncCnt].Stub, Stub, STUBSIZE );
memcpy(&FuncLst[FuncCnt].Stub[4],&FuncLst[FuncCnt],2);FuncCnt++;
}
ExtSyms[ExtCnt].Flag = 2;
ExtSyms[ExtCnt].SymNumb = j;
}
ExtCnt++;
}
}
break;
case PUBDEF: // add to list of available functions
i = 0;
if( Data[i]&0x80 )
{
pubgrp = (Data[i++]&0x7f) << 8;
pubgrp += Data[i++];
}
else
pubgrp = Data[i++];
if( Data[i]&0x80 )
{
pubseg = (Data[i++]&0x7f) << 8;
pubseg += Data[i++];
}
else
pubseg = Data[i++];
if( pubseg == 0 ) // skip the frame
i += 2;
while( i < size-1 )
{
ln = Data[i];
if( ln )
{
strncpy( Name, &Data[i+1], ln );
Name[ln] = '\0';
}
i += ln + 1;
memcpy( &ln, &Data[i], sizeof( int ));
i += 2;
if( Data[i]&0x80 )
i += 2;
else
i++;
for( j=0; j<FuncCnt
&& strcmp( FuncLst[j].Name, Name ); j++ );
Pubs[PubCnt].FuncNumb = j;
Pubs[PubCnt].OffSet = ln;
PubCnt++;
}
break;
case LEDATA:
i = 0;
if( Data[i]&0x80 )
{
dataseg = (Data[i++]&0x7f) << 8;
dataseg += Data[i++];
}
else
dataseg = Data[i++];
memcpy( &dataoff, &Data[i], sizeof( int ));
i += sizeof( int );
if( dataseg == 2 ) // it's for the data segment
{
Dp = &DSptr[DataSize+dataoff];
memcpy( Dp, &Data[i], size - ( i+1 ));
if( LocalSize < dataoff + size - (i+1))
LocalSize = dataoff + size - (i+1);
constseg = LocalSize+DataSize;
}
else if( dataseg == 3 ) // for const segment
{
Dp = &DSptr[constseg+dataoff];
memcpy( Dp, &Data[i], size - ( i+1 ));
if( LocalSize < dataoff + size - (i+1))
LocalSize = dataoff + size - (i+1);
}
else // here is the code
{
if( dataoff == 0 ) LastFunc = malloc( size - (i+1) );
else
LastFunc = realloc( LastFunc, size - (i+1) + dataoff );
Dp = &LastFunc[dataoff];
memcpy( Dp, &Data[i], size-(i+1));
for( j=0; j<PubCnt; j++ )
{
FuncLst[Pubs[j].FuncNumb].Loc = &LastFunc[Pubs[j].OffSet];
}
}
break;
case FIXUPP: // only look at the fixup fields all
// threads are the same.
i = 0;
while( i < size-1 )
{
if( (Data[i])&0x80 ) // its a fixup
{
DROff = ((Data[i]&3)<<8) + Data[i+1];
Loc = Data[i];
i += 2;
FixDat = Data[i++];
FrameIdx = TargetIdx = TargetDisp = 0;
if( !(FixDat&0x80) && (FixDat&0x70) != 0x50 )
/* there is a frame index */
{
if( Data[i]&0x80 )
{
FrameIdx = (Data[i++]&0x7f) << 8;
FrameIdx += Data[i++];
}
else
FrameIdx = Data[i++];
}
if( !(FixDat&8) ) /* thread index */
{
if( Data[i]&0x80 )
{
TargetIdx = (Data[i++]&0x7f) << 8;
TargetIdx += Data[i++];
}
else
TargetIdx = Data[i++];
}
if( !(FixDat&4) )
{
memcpy( &TargetDisp, &Data[i], sizeof( int ));
i += 2;
}
/* fix up FixDat from threads */
if( FixDat&0x80 ) // frame from thread
{
j = ((FixDat&0x70)>>4) + 4;
tmp = Threads[j].Meth << 4;
FixDat = (FixDat&0xf) | tmp;
FrameIdx = Threads[j].Idx;
}
if( FixDat&8 ) // target from a thread
{
j = FixDat&3;
tmp = Threads[j].Meth&3;
FixDat = (FixDat&0xf4) | tmp;
TargetIdx = Threads[j].Idx;
}
switch( Loc&0x1C ) // find what we need
{
case 0x4: // offset fixup
if( (FixDat&7) == 4 )
{
/* get the value to be fixed */
memcpy( &tmp, &Dp[DROff], sizeof(int));
if( TargetIdx == 2 ) // data seg
{
tmp += ((unsigned long)
&DSptr[DataSize])&0xffff;
}
else if( TargetIdx == 3 )
{
tmp += ((unsigned long)
&DSptr[constseg])&0xffff;
}
/* put the fixed number back */
memcpy( &Dp[DROff], &tmp,
sizeof(int));
}
else if((FixDat&7) == 6 )
{
if( !(Loc&0x40) )
{
ltmp = (unsigned long)
(FuncLst[ExtSyms[TargetIdx-1]
.SymNumb].Loc);
ltmp -= (unsigned long) (&Dp[DROff])+2L;
memcpy( &Dp[DROff],<mp, sizeof(int));
}
else // put the offset in
{
memcpy( &Dp[DROff],&Syms[ExtSyms[TargetIdx-1].SymNumb].Offset, sizeof( int ));
}
}
break;
case 0x8: // segment fixup
if( (FixDat&7) == 6 )
{
memcpy( &Dp[DROff], &Syms[ExtSyms[TargetIdx-1].SymNumb].Seg, sizeof( int ));
}
break;
case 0xC: // symbol from target
if( (FixDat&7) == 6 )
{
ptr = FuncLst[ExtSyms
[TargetIdx-1].SymNumb].Stub;
memcpy( &Dp[DROff], &ptr,
sizeof( void *));
}
break;
}
}
else // its a thread
{
j = Data[i]&3;
if( Data[i]&0x40 )
j += 4;
Threads[j].Meth = (Data[i]&0x1C)>>2;
i++;
if( Data[i]&0x80 )
{
tmp = (Data[i++]&0x7f) << 8;
tmp += Data[i++];
}
else
tmp = Data[i++];
Threads[j].Idx = tmp;
}
}
break;
default:
printf( "invalid record: %x size: %d\n", type, size );
break;
}
free( Data );
}
close( fd );
DataSize += LocalSize;
}
[LISTING FOUR]
// DLL.C Implement DLLs for DOS
// 02/12/89 by Gary Syck
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAIN
#include "dll.h"
void
main( int argc, char *argv[] )
{
void (*func)(void);
unsigned char *ptr;
GetData(); // Read the global data
FuncCnt = 2; // make two functions
FuncLst[0].Name = malloc( 10 );
strcpy( FuncLst[0].Name, "_printf" ); // The library function printf
FuncLst[0].Loc = printf;
FuncLst[0].Flag = 1;
memcpy( FuncLst[0].Stub, &Stub, STUBSIZE );
ptr = FuncLst;
memcpy( &FuncLst[0].Stub[1], &ptr, 2 );
FuncLst[1].Name = malloc( 10 );
strcpy( FuncLst[1].Name, "_main" ); // The first function to run
FuncLst[1].Loc = NULL;
FuncLst[1].Flag = 0;
memcpy( FuncLst[1].Stub, &Stub, STUBSIZE );
ptr = &FuncLst[1];
memcpy( &FuncLst[1].Stub[1], &ptr, 2 );
func = FuncLst[1].Stub;
(*func)(); // Call the main function
}
[LISTING FIVE]
// Global data to be used with sample DLL
// make various data items
char Str[] = "Tester equals";
int Flubber=20;
int Tester=14;
[LISTING SIX]
// sample DLL routine
#include <stdio.h>
void main(void);
void Test(void);
extern int Flubber;
extern char Str[];
extern int Tester;
// print hello world and the value of Flubber then call Test
void
main()
{
printf( "Hello, world: %d\n", Flubber );
Test();
}
// print a message and the values of Str and Tester
void
Test()
{
printf( "This is a test function\n%s: %d\n", Str, Tester );
}
[LISTING SEVEN]
// DLL.H Include file for DLL
// 02/12/89 By Gary Syck
#ifdef MAIN
#define EXTERN
#else
#define EXTERN extern
#endif
typedef struct {
char *Name; // Name of the symbol
unsigned Size; // size of the symbol
unsigned Seg; // Segment containing the symbol
unsigned Offset; // Offset for the symbol
} SYMTAB;
#define STUBSIZE 50
typedef struct {
char *Name; // name of the function
void *Loc; // where the function is stored
int Flag; // true if function is executing
unsigned char Stub[STUBSIZE]; // Function to call this function
} FUNCTAB;
SYMTAB Syms[200]; // the symbols found
EXTERN int SymCnt; // The number of symbols
EXTERN int AllocNumb; // The first symbol in the current
// allocation block
EXTERN SYMTAB Syms[]; // list of symbols
EXTERN int SymCnt; // number of symbols
EXTERN unsigned SymSize; // running total of the size of stuff
EXTERN int DataSize; // how many bytes in DataSpace are used
EXTERN FUNCTAB FuncLst[100]; // the list of functions
EXTERN int FuncCnt; // The number of allocated entries
extern unsigned char DataSpace; // room in the data segment
extern char Stub; // This is really a function. It is
// used this way to make sure the
// segment gets used in memcpy
/* record types */
#define THEADR 0x80
#define COMMENT 0x88
#define MODEND 0x8A
#define EXTDEF 0x8C
#define TYPDEF 0x8E
#define PUBDEF 0x90
#define LINNUM 0x94
#define LNAMES 0x96
#define SEGDEF 0x98
#define GRPDEF 0x9A
#define FIXUPP 0x9C
#define LEDATA 0xA0
#define LIDATA 0xA2
#define COMDEF 0xB0
// Function prototypes
void main( int argc, char *argv[] );
void LoadFunc( FUNCTAB *Func );
void GetData(void);
void AllocateSyms(void);